/*Master 485 bus */
/*Simple HD build 2.0 (build 1.0 didn't worked after trying for a long time)*/ 


#include<avr\io.h>
#include<util\delay.h>
#include<avr\interrupt.h>
#include<avr\eeprom.h>
#include<string.h>
#include<stdlib.h>
#include "Twi_eeprom.h"

/*---------- Defines Macros-------*/
#define PC 1
#define BUS 2 
#define MARK 10
#define RS485_TX PORTB |= (1<<PB2)
#define RS485_RX PORTB &= ~(1<<PB2)
#define TX 9
#define RX 3
#define OVERFLOW 200 //about 7 sec delay

#define EEP1 0xA6
#define EEP2 0xA6		//remember to assign addresses here
#define EEP3 0xA6
#define EEP4 0xA6
#define EEPROM_ID_ERROR 0xA6
#define DATA_BLOCK_SIZE 1024
#define STORAGE_ERROR 10
#define STORAGE_OVF 11


/*----------GLOBAL VARIABLES---------*/
volatile uint8_t r_index,index_t,Bytes_left;
volatile uint16_t ovf;
volatile char receive_buffer[200],transmit_buffer[100],Received_packet,toggle,count,t_busy,time_up ;

/*---------FUNCTION DECLARATIONS--------*/

void Usart_Init(void);
void Port_Init(void);
void Timer0_Init(void);
void Mux_Select(char);

char get_data_from_pc(void);
void serve_pc(char *);

void Variable_Init(void);
void usart_puts(char *);
void usart_putchar(char);

void recv_mode(void);
void trans_mode(void);

void recv_mode8(void);
void trans_mode8(void);

void send_packet(char *);
void send_packet2node(char *);
void send_packet2pc(char *);
char Ping(uint8_t addr0);

void Node_status(void);

void store(char *,uint8_t);
void error(uint8_t);

/* -------- M A I N ------------- */
int main(void)
	{
		
	Usart_Init();
	Port_Init();
	Variable_Init();
	Timer0_Init();
	
	sei();
		
		
		Node_status();
		
		
		while(1)
		{
		if(get_data_from_pc() == 1)
				{
					serve_pc((char *)receive_buffer);
					
				}
		}
			
	
	
	return 0;
	}

	
void Usart_Init(void)
	{
		UCSRA = 0x00;
		UCSRB = (1<<TXEN)|(1<<TXCIE)|(1<<RXEN)|(1<<UCSZ2);
		UCSRC = (1<<URSEL)|(3<<UCSZ0);
		UBRRH = 0;
		UBRRL = 35;
	}
	
void Port_Init(void)
	{
		DDRB = 0x0F; //PB0 PB1 PB2 are configured as output for MUX MC14016  and MAX485 RO/RE
		PORTB = 0x00; //Initially all ZERO
		
		//PORTB |= (1<<PB2);
	}
void Timer0_Init(void)
	{
		TCCR0 = 0x05;
		TIMSK = 0x01;
	}
void Mux_Select(char char0)
	{
		if(char0 == PC)
			{PORTB &= ~(1<<PB1); PORTB |= (1<<PB0);}
		else if(char0 == BUS)
			{PORTB &= ~(1<<PB0); PORTB |= (1<<PB1); }
		
		_delay_ms(1);	//To stabilize the mux
		
	}
void Variable_Init(void)
	{
		r_index = 0; index_t = 0;
		Received_packet = 0; 
		toggle = 0;
		count = 0;
		t_busy = 0;
		Bytes_left = 0;
		ovf = 0;
		time_up =0;
	}
	
void usart_puts(char * string0)
	{
		while(!(*string0 == '\0'))
		{
			usart_putchar(*string0);
			string0++;
		}
		while(!(UCSRA & (1<<UDRE)))
		;
		_delay_ms(1);
	}
	
void usart_putchar(char character0)
	{
	while(!(UCSRA & (1<<UDRE)))
	;
		UCSRB &= ~(1<<TXB8);
		UDR = character0;
	}

ISR(USART_RXC_vect)
	{
		
		char temp;
		
		temp = UDR;
		
		//PORTB ^= 1;
		
		receive_buffer[r_index++] = temp;//
		
		if( temp == '$')
			{	
				r_index = 0;
			}	
		else if (temp == '\n' )
			{
				trans_mode();
				receive_buffer[r_index] = '\0';
				Received_packet = 10;
				r_index = 0;
				
			}
		
	}
	
	
ISR(USART_TXC_vect)
	{
		if(Bytes_left > 0)
			{
				UCSRB |= (1<<TXB8);
				UDR = transmit_buffer[index_t++];
				Bytes_left--;
			}
		else
			{
				t_busy = 0;
				
				recv_mode();
			}
		
	}
	
	
ISR(TIMER0_OVF_vect)
	{
		
		
		//(t_busy==1)?(PORTB |= 0x04):(PORTB &= ~0x04);
		ovf++;
		
		if(ovf == 65530 )
		ovf = 0;
		
		if(ovf == OVERFLOW)
		{
			time_up = 1;
		}
		
	}

void recv_mode(void)
	{
		RS485_RX;
		UCSRB = (1<<RXEN)|(1<<RXCIE)|(1<<UCSZ2);
		_delay_us(100);
	}
	
void trans_mode(void)
	{
		RS485_TX;
		UCSRB = (1<<TXEN)|(1<<TXCIE)|(1<<UCSZ2);
		_delay_us(100);
	}
	
void send_packet(char * ptr)//this functions works when its trans_mode();
	{
		while(t_busy==1)	//wait till last packet is sent
		;
		
		t_busy = 1;
		//Now its fine to start packeting.
		
		index_t = 0;
		transmit_buffer[index_t++]  = '$';
		while((*ptr != '\0') && (*ptr != '\r'))
		transmit_buffer[index_t++] = *ptr++;
		
		transmit_buffer[index_t++] = '\r';
		transmit_buffer[index_t] = '\n';
		
		Bytes_left = index_t;
		
		index_t = 1;
		UDR = transmit_buffer[0];
		
		
	}
	
void send_packet2pc(char * ptr1)
	{
		UCSRB &= ~(1<<UCSZ2);//8-bit mode
		send_packet(ptr1);
	}
	
void send_packet2node(char * ptr2)//9-bit mode
	{
		UCSRB |= (1<<UCSZ2);
		send_packet(ptr2);
	}
	
	
	
char Ping(uint8_t addr0)
	{
		while(t_busy==1)	//wait till last packet is sent. @ this is sure
		;
		
		cli();
		UCSRB |= (1<<TXB8);
		UDR = addr0;
		_delay_us(400);
		
		sei();
		
		send_packet2node("ping");
		_delay_ms(50);
		if(Received_packet == 10)
			{
					if((strcmp((char*)receive_buffer,"ok\r\n"))== 0)
					{Received_packet = 0;
					return 1;}
			}
		
			
		return 0;
		
	}
void recv_mode8(void)
	{
		RS485_RX;
		UCSRB = (1<<RXEN)|(1<<RXCIE);
		_delay_us(100);
	}
	
void trans_mode8(void)
	{
		RS485_TX;
		UCSRB = (1<<TXEN)|(1<<TXCIE);
		_delay_us(100);
	}

char get_data_from_pc(void)//waits for PC data returns the function in 
	{
			Mux_Select(PC);
			trans_mode8();
			send_packet2pc(">");
			while(t_busy)
			;
			
			recv_mode8();
			PORTB &= ~(1<<PB2);
			_delay_ms(100);	
			time_up = 0;
			ovf = 0;
			PORTB |= (1<<PB2);
			while(!(time_up || Received_packet))
			;
			PORTB &= ~(1<<PB2);
			
			if(Received_packet == 10)
				{
					Received_packet = 0;
					return 1;
				}
			else	
				trans_mode8();
			return 0;
	}
void serve_pc(char * ptr001)
	{
		char str1[10];char * ptr000;
		ptr000 = str1; uint8_t value0;
		
		ptr000 = strtok(ptr001,"_");
		
		
		
		if((strcmp(ptr000,"help")) == 0)
		{
			//Make a help print function here
		}			
		else if((strcmp(ptr000,"ping")) == 0)
		{
			ptr000 = strtok(NULL,"_");
			
			value0 = atoi(ptr000);
			
			Mux_Select(BUS);
			trans_mode();
			
			if(Ping(value0) == 1)
			{
				Mux_Select(PC);
				trans_mode8();
				send_packet2pc("Node_alive");
				while(t_busy)
				;
				
			}
			else
			{
				Mux_Select(PC);
				trans_mode8();
				send_packet2pc("Node_not_responding");
				while(t_busy)
				;
			}
			
		}
		else if((strcmp(ptr000,"data")) == 0)
		{
			ptr000 = strtok(NULL,"_");
			
			value0 = atoi(ptr000);
			
			Mux_Select(BUS);
			trans_mode();
			
			if(Ping(value0) == 1)
			{	
				while(t_busy==1)	//wait till last packet is sent. @ this is sure
				;
				
				cli();
				UCSRB |= (1<<TXB8);
				UDR = value0;
				_delay_us(400);
				sei();
				
				send_packet2node("data");
				_delay_ms(1000);
				if(Received_packet == 10)
					{
					Received_packet = 0;
					Mux_Select(PC);
					trans_mode8();
					//send_packet2pc("data Received");
					//
					//while(t_busy)
					//;
					//trans_mode8();
					store((char *)receive_buffer,value0);
					
					
					
					
					//
					send_packet2pc((char*)receive_buffer);
					while(t_busy)
					;
					//HERE sTORE THE vALUE OF receive_buffer
					}
				else
					{
					Mux_Select(PC);
					trans_mode8();
					send_packet2pc("Node_has_no_data");
					while(t_busy)
					;
					}
				
			}
		else
			{
				Mux_Select(PC);
				trans_mode8();
				send_packet2pc("Node_not_responding");
				while(t_busy)
				;
			}
			
		}
	
	/*	else if()
		else if()
		else if()
		else if()
		else if()
		else if()		
		else if()
		else if()*/
	
	}
	
void store(char * mem_ptr, uint8_t node_no)
	{
	uint16_t ADDRESS_pointer,offset, temp_var;
			uint8_t EEPROM_ID,value_temp,i;
			char error_flag;
			
			
			error_flag = 0;
			ADDRESS_pointer = 0;
			
			
			if(node_no < 65) //node 1 - 64 in EEP1
				{
					EEPROM_ID = EEP1;
					
					ADDRESS_pointer = (node_no - 1)*DATA_BLOCK_SIZE;
				}
			else if((node_no > 64) && (node_no < 129))//node 65-128 in EEP2
				{
					EEPROM_ID = EEP2;
					ADDRESS_pointer = (node_no - 65)*DATA_BLOCK_SIZE;
				}
			else if((node_no > 128) && (node_no < 193))//node 129-192 in EEP3
				{
					EEPROM_ID = EEP3;
					ADDRESS_pointer = (node_no - 129)*DATA_BLOCK_SIZE;
				}
			else if((node_no > 192) && (node_no < 250))//node 193-250 in EEP4
				{
					EEPROM_ID = EEP4;
					ADDRESS_pointer = (node_no - 193)*DATA_BLOCK_SIZE;
				}
			
			//Now we have the EEPROM_DEV_ID and initial address of data segments for various nodes
			//now just load the LAST written location offset and start writing from there
			//
			//
			
			value_temp = TWI_read_byte(EEPROM_ID,ADDRESS_pointer);
			//this is HighByte so
			offset = ((value_temp & 0x03)<<8);
			value_temp = TWI_read_byte(EEPROM_ID,ADDRESS_pointer+1);
			offset |= value_temp;
			
			temp_var = ADDRESS_pointer + offset + 2;
			
			
			i = 0;
			while(receive_buffer[i] != '\r')
			{
				if((offset+i) > 1000)
					{
						error(STORAGE_OVF);
						break; //don't write further
					}
				if(TWI_write_byte(EEPROM_ID,temp_var++,receive_buffer[i++]) != 1)
					{
					error(STORAGE_ERROR);
					error_flag =1;
					break;
					}
				
			}
			
			if(error_flag == 0)
			{
				offset = offset + i;//new offset on successful op
				TWI_write_byte(EEPROM_ID,ADDRESS_pointer,offset>>8);//HB
				TWI_write_byte(EEPROM_ID,ADDRESS_pointer+1,offset);//LB
			}
			
	}
	
void error(uint8_t mm)
	{      
			uint16_t offset0, ADDRESS0;
			uint8_t value_temp0;
			
			value_temp0 = TWI_read_byte(EEPROM_ID_ERROR,0);
			
			offset0 = (value_temp0 << 8);
			
			value_temp0 = TWI_read_byte(EEPROM_ID_ERROR,1);
			
			offset0 |= value_temp0;
			
			ADDRESS0 = 2 + offset0;
			
			TWI_write_byte( EEPROM_ID_ERROR,ADDRESS0,mm);
			
			offset0++;
			
			
			TWI_write_byte(EEPROM_ID_ERROR,ADDRESS0,offset0>>8);//HB
			TWI_write_byte(EEPROM_ID_ERROR,ADDRESS0+1,offset0);//LB
			
			//Task complete.
			
		
	}

void Node_status(void)
{
		uint8_t i;char asc[5],str0[] = {'N','O','D','E','_','x','x','x','_',' ','A','C','K',' ','\0'};
		for(i = 1; i <= 250;i++)
			{	Mux_Select(BUS);
					
						itoa(i,asc,10);
						if(i<10)
						{
							str0[5] = '0'; 
							str0[6] = '0';
							str0[7] = asc[0];
						}
						else if((i>=10) && (i<100))
						{
							str0[5] = '0'; 
							str0[6] = asc[0];
							str0[7] = asc[1];
						}
						else if((i>=100) && (i<251))
						{
							str0[5] = asc[0]; 
							str0[6] = asc[1];
							str0[7] = asc[2];
						}
				
				if((Ping(i)) == 1)
					{
						trans_mode();
						str0[9] = ' '; 
						str0[10] = 'A';
						
						Mux_Select(PC);
						send_packet2pc(str0);
						while(t_busy == 1)
						;
						trans_mode();
					}
				else
					{
						trans_mode();
						str0[9] = 'N'; 
						str0[10] = 'A';
						
						Mux_Select(PC);
						send_packet2pc(str0);
						while(t_busy == 1)
						;
						trans_mode();
					}
				
			}
}